using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Inventory_Storage : Inventory_Base
{
    public List<Inventory_Item> materialStorageList = new(); //储存材料的列表

    public Inventory_Player playerInventory { get; private set; }

    public void SetPlayerInventory(Inventory_Player inventory) => playerInventory = inventory;

    public bool CanCraftItem(Inventory_Item itemToCraft) => HasEnoughCraft(itemToCraft) && playerInventory.CanAddItem(itemToCraft);

    public void CraftItem(Inventory_Item itemToCraft)
    {
        TryConsumeMaterial(itemToCraft);
        playerInventory.AddItem(itemToCraft);
    }

    //尝试添加物品到材料储存表
    public bool TryAddItemToMaterialStorage(Inventory_Item item)
    {
        var itemToAdd = FindCanStackMaterialStorage(item);

        if (materialStorageList.Count >= maxInventoryCount)
            return false;
        if (itemToAdd != null)
            itemToAdd.AddStackSize();
        else
        {
            Inventory_Item newItemToAdd = new(item.itemData);
            materialStorageList.Add(newItemToAdd);
        }

        OnTriggerUpdateUI();
        materialStorageList.OrderBy(item => item.itemData);
        return true;
    }

    //判断是否有足够的材料制作物品
    private bool HasEnoughCraft(Inventory_Item itemToCraft)
    {
        foreach (var material in itemToCraft.itemData.materials)
        {
            if (GetMaterialTotalQuantity(material.materialData) < material.requireMaterialCount)
                return false;
        }
        return true;
    }

    //尝试消耗材料
    private void TryConsumeMaterial(Inventory_Item itemToConsume)
    {
        int neededConsumeCount;

        foreach (var material in itemToConsume.itemData.materials)
        {
            neededConsumeCount = material.requireMaterialCount;

            neededConsumeCount -= ConsumeMaterial(playerInventory.itemList, material);

            if (neededConsumeCount > 0)
                neededConsumeCount -= ConsumeMaterial(itemList, material);

            if (neededConsumeCount > 0)
                neededConsumeCount -= ConsumeMaterial(materialStorageList, material);
        }
    }

    //传入所需删除的材料的信息
    //删除制作所需的库存材料，在当前传入的列表中删除
    //返回删除的材料数量
    private int ConsumeMaterial(List<Inventory_Item> itemList, ItemCraftMaterialInfo itemToConsume)
    {
        //当前删除的材料数量，需要删除的材料数量
        int consumeAmount = 0, needToConsume = itemToConsume.requireMaterialCount;

        foreach (var item in itemList)
        {
            if (item.itemData != itemToConsume.materialData)
                continue;
            //如果（当前所需删除的数量-当前已经删除的数量）大于当前遍历的物品的堆数量，
            // 移除的数量为当前遍历的物品的堆数量，反之取（当前所需删除的数量-当前已经删除的数量）
            int removeAmount = Mathf.Min(item.stackSize, needToConsume - consumeAmount);

            //当前遍历的物品删除移除的数量
            item.stackSize -= removeAmount;
            //当前删除的物品数量+移除的数量
            consumeAmount += removeAmount;

            //判断当前物品是否已经完全删除
            if (item.stackSize <= 0)
                itemList.Remove(item);

            if (consumeAmount >= needToConsume)
                break;
        }
        return consumeAmount;
    }


    //查找材料列表的物品
    public Inventory_Item FindMaterialStorageItem(Inventory_Item itemToFind) => materialStorageList.Find(target => target.itemData == itemToFind.itemData);
    private Inventory_Item FindCanStackMaterialStorage(Inventory_Item itemToFind) =>
        materialStorageList.Find(match => match.itemData == itemToFind.itemData && match.CanAddStackSize());

    public void FromPlayerToStorage(Inventory_Item item, bool isFullOpera)
    {
        int loopCount = isFullOpera ? item.stackSize : 1;
        for (int i = 0; i < loopCount; i++)
        {
            Inventory_Item itemToTransform = new(item.itemData);

            playerInventory.RemoveOneItemInOneSlot(item);

            AddItem(itemToTransform);
        }

        OnTriggerUpdateUI();
    }

    public void FromStorageToPlayer(Inventory_Item item, bool isFullOpera)
    {
        int loopCount = isFullOpera ? item.stackSize : 1;

        for (int i = 0; i < loopCount; i++)
        {
            if (playerInventory.CanAddItem(item))
            {
                Inventory_Item itemToTransform = new(item.itemData);

                RemoveOneItemInOneSlot(itemToTransform);

                playerInventory.AddItem(itemToTransform);
            }
        }

        OnTriggerUpdateUI();
    }

    public int GetMaterialTotalQuantity(ItemDataSO material)
    {
        int playerInventoryCount = GetItemListMaterialCount(playerInventory.itemList, material);
        int materialStorageCount = GetItemListMaterialCount(materialStorageList, material);
        int storageCount = GetItemListMaterialCount(itemList, material);
        return playerInventoryCount + materialStorageCount + storageCount;
    }

    private int GetItemListMaterialCount(List<Inventory_Item> items, ItemDataSO material)
    {
        int total = 0;
        foreach (var item in items)
            if (item.itemData == material)
                total += item.stackSize;

        return total;
    }

    public override void SaveData(ref GameData gameData)
    {
        gameData.storage.Clear();

        foreach (var item in itemList)
        {
            if (item == null || item.itemData == null)
                continue;
            string saveId = item.itemData.saveId;
            if (gameData.storage.ContainsKey(saveId) == false)
                gameData.storage[saveId] = 0;
            gameData.storage[saveId] += item.stackSize;
        }

        gameData.storageMaterials.Clear();

        foreach (var item in materialStorageList)
        {
            if (item == null || item.itemData == null)
                continue;
            string saveId = item.itemData.saveId;
            if (gameData.storageMaterials.ContainsKey(saveId) == false)
                gameData.storageMaterials[saveId] = 0;
            gameData.storageMaterials[saveId] += item.stackSize;
        }

        
    }
    public override void LoadData(GameData gameData)
    {
        itemList.Clear();
        foreach (var item in gameData.storage)
        {
            string saveId = item.Key;
            ItemDataSO data = itemDataBase.GetItemData(saveId);
            if (data == null)
                continue;

            for (int i = 0; i < item.Value; i++)
            {
                Inventory_Item itemToLoad = new(data);
                AddItem(itemToLoad);
            }
        }

        materialStorageList.Clear();
        foreach (var item in gameData.storageMaterials)
        {
            string saveId = item.Key;
            ItemDataSO data = itemDataBase.GetItemData(saveId);
            if (data == null)
                continue;

            for (int i = 0; i < item.Value; i++)
            {
                Inventory_Item itemToLoad = new(data);
                TryAddItemToMaterialStorage(itemToLoad);
            }
        }
    }
    
}
